package quads;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.Random;

import util.AudioClipBalanced;



public abstract class MarchQuad  {
	
	//private static final int DEFAULT_BEATS = 1;
	//private static final int DEFAULT_DURATION = 250;
	
	
	private int type;
	

	
	private int row;
	private int col;

	
	public boolean[][] colors = new boolean[2][2];
	public boolean[][] image;
	
	
	private int transitionCeiling = 0;
	
	private boolean alive = true;
	protected boolean newType = false;
	private boolean reverse = false;
	
	private int pulseTimer;
	
	Random rand = new Random();
	
	protected AudioClipBalanced[] sounds = new AudioClipBalanced[16];
	
	
	public MarchQuad(boolean[][] bools) {
		this.image = bools;
		
		
		initSounds();
		
	}
	
	protected abstract int getNumBeats();

	protected abstract void initSounds();

	public void calcType() {
		// check for out of bounds...
		
		
		int oldType = type;
		
		type = 0;
		try {
			if (image[row][col]) type += 1;
			if (image[row][col+1]) type += 2;
			if (image[row+1][col]) type += 4;
			if (image[row+1][col+1]) type += 8;
		} catch (ArrayIndexOutOfBoundsException e) {
			alive = false;
			type = -1;
		}
		
		newType = type != oldType;
		//return type;
		
	}
	
	public void setPosition(int row, int column) {
		
			calcType();
			
			setColors();
			
			this.row = row; this.col = column;
			
	}
	
	public void start() {
		iterate();
	}
	
	public void iterate() {
		calcType();
		
		move();
		
		playSound(type, newType);
		
		
	}
	
	private void setColors() {
		
		
		colors[0][0] = (type & 1) > 0;
		
		colors[0][1] = (type & 2) > 0;
		
		colors[1][0] = (type & 4) > 0;
		
		colors[1][1] = (type & 8) > 0;
		
		
	}

	private void move() {
		//GWT.log("Type: " + type);
		// N = 0; E = 1; S=2; W=3;
		int direction = -1;
		
		if (!reverse) {
		
			switch (type) {
			case 0:
			case 4:
			case 7:
			case 15:
			
			case 5:
				direction = 2;
				break;
			case 1:
			case 3:
			case 11:
			
				direction = 3;
				break;
			case 2:
			case 10:
			case 14:
				direction = 0;
				break;
			case 8:
			case 12:
			case 13:
				direction = 1;
				break;
			case 6:
				direction = rand.nextBoolean() ? 2 : 0;
				break;
			case 9:
				direction = rand.nextBoolean() ? 1 : 3;
				break;
			default:
				direction = -1;
			
			}
		}
		
		else {
			// N = 0; E = 1; S=2; W=3;
			switch (type) {
			case 0:
			case 8:
			case 10:
			case 11:
			case 15:
			
			
				direction = 2;
				break;
				
			case 4:
			case 12:
			case 14:
				
				direction = 3;
				break;
			
			case 1:
			case 5:
			case 13:
				direction = 0;
				break;
			
			case 2:
			case 3:
			case 7:
				direction = 1;
				break;
			
			case 9:
				direction = rand.nextBoolean() ? 2 : 0;
				break;
			case 6:
				direction = rand.nextBoolean() ? 1 : 3;
				break;
			default:
				direction = -1;
			
			}
			
		}
		
		
		switch (direction) {
		case 0:
			row--;
			if (row < 0) {
				row = 0;
				reverse = !reverse;
			}
			break;
		case 1:
			col++;
			if (col > image[0].length - 2) {
				col = image[0].length - 2;
				reverse = !reverse;
			}
			break;
		case 2:
			row++;
			if (row > image.length - 2) {
				row = image.length - 2;
				reverse = !reverse;
			}
			break;
		case 3:
			col--;
			if (col < 0) {
				col = 0;
				reverse = !reverse;
			}
			break;
		default:
			break;
		}
		
		
		if (row < transitionCeiling) {
			row = transitionCeiling;
		}
		

		setPosition(row, col);
		
	}

	protected void playSound(int type, boolean newType) {
		//System.out.println("ding " + type);
		//drum.play();
		//Toolkit.getDefaultToolkit().beep();
		
		//float balance = col * 2.0f / image[0].length - 1;
		
		if (type >= 0 && newType) {
			sounds[type].play(getGain(type));
		}
	}

	
	public void kill() {
		alive = false;
		
	}

	public boolean handlePulse() {
		
		if (!alive) return false;
		
		if (pulseTimer <= 0) {
			iterate();
			pulseTimer = getNumBeats();
			pulseTimer--;
			return true;
		}
		
		pulseTimer--;
		return false;
	}

	public int getRow() {
		return row;
	}

	public int getCol() {
		return col;
	}
	
	
	public void paint(Graphics2D g, Rectangle r) {
		
		int cellW = r.width / 2;
		int cellH = r.height / 2;
		
		setColor(g, colors[0][0]);
		g.fillRect(r.x, r.y, cellW, cellH);
		
		setColor(g, colors[0][1]);
		g.fillRect(r.x + cellW, r.y, cellW, cellH);
		
		setColor(g, colors[1][0]);
		g.fillRect(r.x, r.y + cellH, cellW, cellH);
		
		setColor(g, colors[1][1]);
		g.fillRect(r.x + cellW, r.y + cellH, cellW, cellH);
		
		g.setColor(getBorderColor());
		g.setStroke(new BasicStroke(3));
		
		g.drawRect(r.x, r.y, r.width, r.height);
		
		
	}
	
	public int getType() {
		return type;
	}
	
	private void setColor(Graphics2D bg, boolean b) {
		if (b) bg.setColor(getTrueColor());
		else bg.setColor(getFalseColor());
	}

	protected abstract Color getFalseColor();

	protected abstract Color getTrueColor();
	
	protected abstract Color getBorderColor();
	
	protected float getGain(int type) {
		return 1;
	}
	
	public void setTransitionCeiling(int ceiling) {
		if (row < ceiling) {
			row = ceiling;
		}
	}
	
	public void setBools(boolean[][] bools, int rowSubtraction) {
		this.image = bools;
		this.row -= rowSubtraction;
	}
	
}
